package main

import (
	"crypto/rand"
	"fmt"
	"math/big"
	"time"
)

// JobArgs struct. Passing Parameters and Return Value Usage
func NewJobArgs(name string, storage *[]int) Job {
	return &JobArgs{
		WorkersName:   name,
		isfinish:      false,
		resultStorage: storage,
	}
}

type JobArgs struct {
	WorkersName   string
	isfinish      bool
	resultStorage *[]int
}

func (j *JobArgs) Do() {
	j.isfinish = false
	fmt.Println(j.WorkersName, "started working.")

	result, _ := rand.Int(rand.Reader, big.NewInt(1024))
	time.Sleep(3 * time.Second)
	(*j.resultStorage) = append((*j.resultStorage), int(result.Int64()))

	fmt.Println(j.WorkersName, "work is done. Push result:", result)
	j.isfinish = true
}

func (j *JobArgs) IsFinish() bool {
	return j.isfinish
}

// JobSimple struct. Just run.

func NewJobSimple() Job {
	return &JobSimple{}
}

type JobSimple struct {
	isfinish bool
}

func (j *JobSimple) Do() {
	j.isfinish = false
	fmt.Println("Simple started working.")

	result, _ := rand.Int(rand.Reader, big.NewInt(1024))
	time.Sleep(3 * time.Second)

	fmt.Println("Simple work is done. result:", result)
	j.isfinish = true
}

func (j *JobSimple) IsFinish() bool {
	return j.isfinish
}

func JobSimpleStart(processNumber int) {
	running_jobs := []Job{}
	wp := NewWorkerPool(processNumber)
	wp.Run()
	go func() {
		for i := 0; i < 5; i++ {
			job := NewJobSimple()
			running_jobs = append(running_jobs, job)
			wp.JobQueue <- job
		}
	}()

	for {
		time.Sleep(time.Millisecond * 400)
		isBreak := true
		// Completion check function
		for i := range running_jobs {
			if !running_jobs[i].IsFinish() {
				isBreak = false
			}
		}

		// Finish check
		if isBreak {
			break
		}
	}
}

func main() {
	var start_time int64

	// JobArgs
	fmt.Println("# JobArgs")
	start_time = time.Now().UnixNano()
	wm := NewWorkManager([]string{"Leon", "Lucas", "Luka", "Tim", "Finn"}, NewJobArgs)
	wm.Start(3)
	wm.Wait()
	fmt.Println("Use time:", float64((time.Now().UnixNano()-start_time))/1000000000, 's')
	fmt.Println("All results:", wm.AllResults)

	// JobSimple
	fmt.Println("\n# JobSimple")
	start_time = time.Now().UnixNano()
	JobSimpleStart(3)
	fmt.Println("Use time:", float64((time.Now().UnixNano()-start_time))/1000000000, 's')
}

/* Result
$ go run template.go job.go utils.go worker.go workerpool.go workmanager.go
# JobArgs
Leon started working.
Lucas started working.
Luka started working.
Lucas work is done. Push result: 504
Leon work is done. Push result: 966
Finn started working.
Tim started working.
Luka work is done. Push result: 745
Get result: 966
Get result: 745
Get result: 504
Finn work is done. Push result: 509
Tim work is done. Push result: 376
Get result: 509
Get result: 376
Use time: 6.4144043 115
All results: [966 745 504 509 376]

# JobSimple
Simple started working.
Simple started working.
Simple started working.
Simple work is done. result: 389
Simple started working.
Simple work is done. result: 961
Simple started working.
Simple work is done. result: 371
Simple work is done. result: 947
Simple work is done. result: 882
Use time: 6.0106823 115

*/
